package com.sgcc.nfc.lock.data.repository

import com.sgcc.nfc.lock.core.network.NetworkResult
import com.sgcc.nfc.lock.core.network.safeApiCall
import com.sgcc.nfc.lock.core.network.safeApiCallVoid
import com.sgcc.nfc.lock.data.local.dao.RoomDao
import com.sgcc.nfc.lock.data.local.mapper.toDomain
import com.sgcc.nfc.lock.data.local.mapper.toEntity
import com.sgcc.nfc.lock.data.remote.api.RoomApi
import com.sgcc.nfc.lock.data.remote.api.RoomRequest
import com.sgcc.nfc.lock.domain.model.PagedList
import com.sgcc.nfc.lock.domain.model.Room
import com.sgcc.nfc.lock.domain.repository.RoomRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.first

class RoomRepositoryImpl @Inject constructor(
    private val roomApi: RoomApi,
    private val roomDao: RoomDao
) : RoomRepository {

    override suspend fun getRooms(
        page: Int,
        pageSize: Int,
        regionId: Long?,
        keyword: String?
    ): NetworkResult<PagedList<Room>> {
        val response = safeApiCall {
            roomApi.getRooms(page, pageSize, regionId, keyword)
        }
        return when (response) {
            is NetworkResult.Success -> {
                val paged = response.data.map { it.toDomain() }
                roomDao.upsertAll(paged.data.map { it.toEntity() })
                NetworkResult.Success(paged)
            }
            is NetworkResult.Error -> {
                val local = roomDao.observeRooms().first().map { it.toDomain() }
                if (local.isNotEmpty()) {
                    NetworkResult.Success(
                        PagedList(local, 1, local.size.toLong(), local.size.toLong(), 1)
                    )
                } else {
                    response
                }
            }
            NetworkResult.Loading -> NetworkResult.Loading
        }
    }

    override suspend fun getRoomDetail(roomId: Long): NetworkResult<Room> {
        val response = safeApiCall { roomApi.getRoomDetail(roomId) }
        return when (response) {
            is NetworkResult.Success -> NetworkResult.Success(response.data.toDomain())
            is NetworkResult.Error -> response
            NetworkResult.Loading -> NetworkResult.Loading
        }
    }

    override suspend fun createRoom(params: RoomRepository.CreateRoomParams): NetworkResult<Unit> {
        return safeApiCallVoid {
            roomApi.createRoom(params.toRequest())
        }
    }

    override suspend fun updateRoom(params: RoomRepository.UpdateRoomParams): NetworkResult<Unit> {
        return safeApiCallVoid {
            roomApi.updateRoom(params.roomId, params.toRequest())
        }
    }

    override suspend fun deleteRoom(roomId: Long): NetworkResult<Unit> {
        return safeApiCallVoid { roomApi.deleteRoom(roomId) }
    }

    private fun RoomRepository.CreateRoomParams.toRequest(): RoomRequest = RoomRequest(
        roomName = roomName,
        regionId = regionId,
        longitude = longitude,
        latitude = latitude,
        address = address
    )

    private fun RoomRepository.UpdateRoomParams.toRequest(): RoomRequest = RoomRequest(
        roomName = roomName,
        regionId = regionId,
        longitude = longitude,
        latitude = latitude,
        address = address
    )
}